#include "../handler_task.h"
#include "../../driver/heat/motors.h"
#include "../../driver/heat/ntc_sensor.h"
#include "../../driver/heat/parts.h"
#include "../../driver/heat/sensor.h"
#include "../../service/salve_conn.h"
#include "../../conn/proto.h"
#include "./draw_task.h"
#include "./heat_task.h"
#include "../../service/heat/pick_service.h"
#include "../../service/heat/config_info.h"

namespace task {

using namespace driver;
using namespace conn;
using namespace service;
using namespace utils;

static Error on_draw_ctrl(const Message &msg) {
    uint8_t type;
    Error err = msg.parse(type);
    if (err) {
        goto finish;
    }
    switch (type) {
        case 0: drawTask->draw_auto(); break;
        case 1: drawTask->draw_stop(); break;
        default: err = ec::INVALID; break;
    }
finish:
    return err;
}

static Error on_stir_box_ctrl(const Message &msg) {
    uint8_t type;
    Error err = msg.parse(type);
    if (err) {
        goto finish;
    }
    switch (type) {
        case 0: err = motors->stir_box_open(); break;
        case 1: err = motors->stir_box_close(); break;
        default: err = ec::INVALID; break;
    }
finish:
    return err;
}

static Error on_water_motor_ctrl(const Message &msg) {
    uint8_t type;
    Error err = msg.parse(type);
    if (err) {
        goto finish;
    }
    switch (type) {
        case 0: err = motors->water_left(); break;
        case 1: err = motors->water_right(); break;
        default: err = ec::INVALID; break;
    }
finish:
    return err;
}

static Error on_ice_motor_ctrl(const Message &msg) {
    uint8_t type;
    Error err = msg.parse(type);
    if (err) {
        goto finish;
    }
    switch (type) {
        case 0: err = motors->ice_left(); break;
        case 1: err = motors->ice_right(); break;
        default: err = ec::INVALID; break;
    }
finish:
    return err;
}

static Error on_parts_ctrl(const Message &msg) {
    uint8_t type, val;
    uint16_t v;
    Error err = msg.parse(type, val);
    if (err) {
        goto finish;
    }
    v = (type << 8) + val;
    switch (v) {
        case 0x0100: parts->water_heat_open(); break;
        case 0x0101: parts->water_heat_close(); break;

        case 0x0200: parts->steam_heat_open(); break;
        case 0x0201: parts->steam_heat_close(); break;

        case 0x0300: parts->water_pump_open(); break;
        case 0x0301: parts->water_pump_close(); break;

        case 0x0400: parts->clean_pump_open(); break;
        case 0x0401: parts->clean_pump_close(); break;

        case 0x0500: parts->water_valve_open(); break;
        case 0x0501: parts->water_valve_close(); break;

        case 0x0600: parts->clean_valve_open(); break;
        case 0x0601: parts->clean_valve_close(); break;

        case 0x0700: parts->steam_pump_open(); break;
        case 0x0701: parts->steam_pump_close(); break;

        case 0x0800: parts->steam_valve_open(); break;
        case 0x0801: parts->steam_valve_close(); break;

        case 0x0900: parts->bucket1_pump_open(); break;
        case 0x0901: parts->bucket1_pump_close(); break;

        case 0x0A00: parts->bucket2_pump_open(); break;
        case 0x0A01: parts->bucket2_pump_close(); break;

        case 0x0B00: parts->ro_exit_valve_open(); break;
        case 0x0B01: parts->ro_exit_valve_close(); break;

        case 0x0C00: parts->ro_enter_valve_open(); break;
        case 0x0C01: parts->ro_enter_valve_close(); break;

        case 0x0D00: parts->stir_motor_open(); break;
        case 0x0D01: parts->stir_motor_close(); break;

        case 0x0E00: parts->drop_valve_open(); break;
        case 0x0E01: parts->drop_valve_close(); break;

        default: err = ec::INVALID; break;
    }

finish:
    return err;
}

static Error on_init() {
    Error err = motors->stir_box_open();
    if (err) {
        goto finish;
    }
    err = motors->ice_left();
    if (err) {
        goto finish;
    }
    err = motors->water_left();
    if (err) {
        goto finish;
    }
finish:
    return err;
}

static Error on_set_flow(const Message &msg) {
    uint16_t arg;
    Error err = msg.parse(arg);
    if (err) {
        goto finish;
    }
    if (arg == 0) {
        err = ec::INVALID;
        goto finish;
    }
    configInfo->flow_count_1000ml = arg;
    err = configInfo.save();
finish:
    return err;
}

static Error on_draw_water(const Message &msg) {
    uint8_t ml;
    Error err = msg.parse(ml);
    if (err) {
        goto finish;
    }
    err = draw_water(ml);
finish:
    return err;
}

static Error on_pre_heat_ctrl(const Message &msg) {
    uint8_t ctrl, water, steam;
    Error err = msg.parse(ctrl, water, steam);
    if (err) {
        goto finish;
    }
    switch (ctrl) {
        case 0: heatTask->heat(water, steam); break;
        case 1: heatTask->stop(); break;
        default: err = ec::INVALID;
    }
finish:
    return err;
}

static Error on_drop_steam(const Message &msg) {
    uint8_t duration, temp;
    Error err = msg.parse(duration, temp);
    if (err) {
        goto finish;
    }
    err = drop_steam(duration, temp);
finish:
    return err;
}

static Error on_stir_powder(const Message &msg) {
    uint8_t water, temp;
    Error err = msg.parse(water, temp);
    if (err) {
        goto finish;
    }
    err = stir_powder(water, temp);
finish:
    return err;
}

static Error on_clean(const Message &msg) {
    uint8_t sec;
    Error err = msg.parse(sec);
    if (err) {
        goto finish;
    }
    err = clean(sec);
finish:
    return err;
}

static Error on_pre_water(const Message &msg) {
    uint8_t ml, temp;
    Error err = msg.parse(ml, temp);
    if (err) {
        goto finish;
    }
    err = pre_water(ml, temp);
finish:
    return err;
}

void HandlerTask::dispatch_impl(const Message &msg) {
    Error err;
    switch (msg.conn_info.req) {
        case proto::REQ_HEAT_DRAW_CTRL:
            err = on_draw_ctrl(msg);
        break;

        case proto::REQ_HEAT_STIR_BOX_CTRL:
            err = on_stir_box_ctrl(msg);
        break;

        case proto::REQ_HEAT_WATER_MOTOR_CTRL:
            err = on_water_motor_ctrl(msg);
        break;

        case proto::REQ_HEAT_ICE_MOTOR_CTRL:
            err = on_ice_motor_ctrl(msg);
        break;

        case proto::REQ_HEAT_PARTS_CTRL:    
            err = on_parts_ctrl(msg);
        break;

        case proto::REQ_HEAT_INIT:
            err = on_init();
        break;

        case proto::REQ_HEAT_SET_FLOW:
            err = on_set_flow(msg);
        break;

        case proto::REQ_HEAT_DRAW_WATER:
            err = on_draw_water(msg);
        break;

        case proto::REQ_HEAT_PRE_HEAT_CTRL:
            err = on_pre_heat_ctrl(msg);
        break;

        case proto::REQ_HEAT_DROP_STEAM:
            err = on_drop_steam(msg);
        break;

        case proto::REQ_HEAT_STIR_POWDER:
            err = on_stir_powder(msg);
        break;

        case proto::REQ_HEAT_CLEAN:
            err = on_clean(msg);
        break;

        case proto::REQ_HEAT_PRE_WATER:
            err = on_pre_water(msg);
        break;

        default: 
            err = ec::INVALID;
        break;
    }
    salveConn->response(msg, err);
}

}
